///
/// ArmyBodger 3
/// (c)2010 richyp
///
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ArmyBodger.Core;

namespace ArmyBodger.UI {
    /// <summary>
    /// The List Control that contains the Entries for the current File
    /// </summary>
    public partial class EntryListControl : Panel {
        /// <summary>
        /// Default Constructor
        /// </summary>
        public EntryListControl() {
            InitializeComponent();
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.Resize += new EventHandler(EntryListControl_Resize);
            this.AutoScroll = true;
        }
        /// <summary>
        /// The total item at the bottom of the list
        /// </summary>
        protected EntryItem listTotalItem = null;
        /// <summary>
        /// Error message to display
        /// </summary>
        public string ErrorMessage { get; set; }
        /// <summary>
        /// Collection of the current EntryItems
        /// </summary>
        protected List<EntryItem> items = new List<EntryItem>();
        /// <summary>
        /// Collection of the categories currently used
        /// </summary>
        protected List<string> categories = new List<string>();
        /// <summary>
        /// Indexer to get Entry by offset
        /// </summary>
        /// <param name="index">offset of Entry</param>
        /// <returns>Entry at offset</returns>
        public Entry this[int index] {
            get {
                return this.GetEntries()[index];
            }
        }
        /// <summary>
        /// Set the main form
        /// </summary>
        public BodgerForm Form { get; set; }
        /// <summary>
        /// Get all Entry objects with the name "name"
        /// </summary>
        /// <param name="name">The name of the Entry objects to get</param>
        /// <returns>A collection of Entry object</returns>
        public EntryCollection this[string name] {
            get {
                return this.GetEntries().GetEntriesByName(name);
            }
        }
        /// <summary>
        /// Check the Valididty of the current list
        /// </summary>
        public void CheckValidity() {
            if (this.Form != null && this.Form.CurrentArmyBook != null) {
                ArmyBook book = this.Form.CurrentArmyBook;
                GameSystem gs = this.Form.GameSystems[book.Header.GameSystem];
                if (!String.IsNullOrEmpty(gs.Header.ListCheckEvent)) {
                    this.ScriptCore.Execute(gs.Header.ListCheckEvent);
                }
            }
        }
        /// <summary>
        /// Selected Item was changed
        /// </summary>
        /// <param name="selected">The EntryItem selected</param>
        public void OnSelectionChange(EntryItem selected) {
            this.Form.EquipmentPanel.CurrentEntry = selected;
        }
        /// <summary>
        /// The ScriptEngine
        /// </summary>
        public ScriptCore ScriptCore { get; set; }
        /// <summary>
        /// Resize the EntryItem objects to match the width of this control
        /// </summary>        
        public void ResizeRender() {
            foreach (Control control in this.Controls) {
                control.Width = this.Width;
            }
        }
        /// <summary>
        /// Remove the specified Entry object from this List
        /// </summary>
        /// <param name="entry">The Entry to remove</param>
        public void RemoveEntry(Entry entry) {
            EntryItem removeMe = null;
            foreach (EntryItem item in this.items) {
                if (item.Entry == entry) {
                    removeMe = item;
                    break;
                }
            }
            if (removeMe != null) {
                string category = removeMe.Entry.Category;
                this.items.Remove(removeMe);
                bool exists = false;
                foreach (EntryItem entryItem in this.items) {
                    if (entryItem.Entry.Category == category) {
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    this.categories.Remove(category);
                }
                this.Render();
                this.CheckValidity();
                this.Render();
            }
        }
        /// <summary>
        /// Convert the List Entry objects to XML so it can be serialized
        /// </summary>
        /// <returns>XML Representation of the List</returns>
        public string ToXml() {
            StringBuilder xml = new StringBuilder();
            xml.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
            xml.Append("<list>\n");
            xml.Append("  <gameSystem>" + BodgerForm.MainForm.CurrentArmyBook.Header.GameSystem + "</gameSystem>\n");
            xml.Append("  <armyBook>" + BodgerForm.MainForm.CurrentArmyBook.Header.Name + "</armyBook>\n");
            foreach (Entry entry in this.GetEntries()) {
                xml.Append(entry.ToXml());
            }
            xml.Append("</list>\n");
            return xml.ToString();
        }
        protected bool rendering = false;
        /// <summary>
        /// Draw the control and its items.
        /// </summary>
        public void Render() {
            if (!this.rendering) {
                this.rendering = true;
                int armyTotal = this.Total;
                this.Controls.Clear();
                int top = 0;
                foreach (string category in this.categories) {
                    EntryItem categoryItem = new EntryItem(null);
                    categoryItem.fromColor = Color.FromArgb(200, 200, 240);
                    categoryItem.Category = category;
                    categoryItem.Top = top;
                    categoryItem.Height = 20;
                    categoryItem.Width = this.Width;
                    categoryItem.Left = 0;
                    top += categoryItem.Height;
                    this.Controls.Add(categoryItem);
                    int pointsTotal = 0;
                    foreach (EntryItem item in this.items) {
                        if (item.Category == category) {
                            item.Width = this.Width;
                            item.Left = 0;
                            item.Top = top;
                            top += item.Height;
                            //item.Selected = false;
                            item.SetButtonStates();
                            this.Controls.Add(item);
                            pointsTotal += item.Entry.Cost;
                        }
                    }
                    int totalPoints = this.Form.PointsLevel;
                    categoryItem.Category += " (" + pointsTotal.ToString() + "pts / "+ (Math.Round((double)((100.0*pointsTotal)/totalPoints))).ToString() + "%)";
                }
                EntryItem totalItem = new EntryItem(null);
                totalItem.TotalItem = true;
                totalItem.Category = "Total: " + this.Total + " pts";
                totalItem.Height = 20;
                totalItem.fromColor = Color.FromArgb(220, 220, 240);
                totalItem.Top = top;
                totalItem.Width = this.Width;
                totalItem.Left = 0;
                this.listTotalItem = totalItem;
                if (!String.IsNullOrEmpty(this.ErrorMessage)) {
                    totalItem.ErrorMessage = this.ErrorMessage;
                }
                totalItem.Dock = DockStyle.Bottom;
                this.Controls.Add(totalItem);
                if (this.Form != null && this.Form.EquipmentPanel != null) {
                    this.Form.EquipmentPanel.UpdatePanel();
                }
                this.rendering = false;
            }
            
        }
        /// <summary>
        /// Update the list total
        /// </summary>
        public void UpdateTotal() {
            if (this.listTotalItem != null) {
                this.listTotalItem.Category = "Total: " + this.Total + " pts";
                this.listTotalItem.Refresh();
            }
        }
        /// <summary>
        /// Get the total cost of all the Entry objects
        /// </summary>
        public int Total {
            get {
                int total = 0;
                foreach (Entry entry in this.GetEntries()) {
                    total += entry.Cost;
                }
                return total;
            }
        }
        /// <summary>
        /// Deselect any items that maybe selected
        /// </summary>
        public void DeselectAll() {
            foreach (EntryItem item in this.items) {
                item.Selected = false;
                item.SetButtonStates();
            }
            if (this.Form != null && this.Form.EquipmentPanel != null) {
                this.Form.EquipmentPanel.CurrentEntry = null;
            }
            this.Render();
        }
        /// <summary>
        /// Get the currently selected EntryItem's Entry
        /// </summary>
        public Entry SelectedEntry {
            get {
                foreach (EntryItem item in this.items) {
                    if (item.Selected) {
                        return item.Entry;
                    }
                }
                return null;
            }
            set {
                this.DeselectAll();
                foreach (EntryItem item in this.items) {
                    if (item.Entry == value) {
                        item.Selected = true;
                        item.SetButtonStates();
                        this.Render();
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Add an Entry to the list and encapsulate it in an EntryItem object
        /// </summary>
        /// <param name="entry">The Entry object to encapsulate</param>
        public void AddEntry(Entry entry) {
            if (!this.categories.Contains(entry.Category)) {
                this.categories.Add(entry.Category);
                this.categories.Sort();
            }
            EntryItem item = new EntryItem(entry);
            item.Category = entry.Category;
            this.items.Add(item);
            this.Render();
            this.CheckValidity();
            this.Render();
        }
        /// <summary>
        /// Clear the list
        /// </summary>
        public void Clear() {
            this.Controls.Clear();
            this.Items.Clear();
            this.categories.Clear();
            this.Render();
        }
        /// <summary>
        /// The Items in this List
        /// </summary>
        public List<EntryItem> Items {
            get {
                return this.items;
            }
        }
        /// <summary>
        /// Get a collection of all the Entry objects in this list
        /// </summary>
        /// <returns>An EntryCollection of all the current Entry objects</returns>
        public EntryCollection GetEntries() {
            EntryCollection entries = new EntryCollection();
            /*foreach (EntryItem item in this.items) {
                if (item.Entry != null) {
                    entries.Add(item.Entry);
                }
            }*/
            foreach (Control c in this.Controls) {
                if (c is EntryItem) {
                    EntryItem i = (EntryItem)c as EntryItem;
                    if (i.Entry != null && !String.IsNullOrEmpty(i.Entry.Name)) {
                        entries.Add(i.Entry);
                    }
                }
            }
            return entries;
        }
        /// <summary>
        /// Overriden OnPaint method
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e) {
            base.OnPaint(e);
            e.Graphics.FillRectangle(Brushes.DarkGray, this.ClientRectangle);
        }
        /// <summary>
        /// The control was resized, resize the children to match
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void EntryListControl_Resize(object sender, EventArgs e) {
            this.ResizeRender();
        }
    }
}
